package com.ruoyi.biz.service;

import com.ruoyi.biz.domain.BizCost;
import com.ruoyi.biz.domain.BizProject;
import com.ruoyi.biz.domain.BizReceipt;
import com.ruoyi.biz.domain.BizSector;
import com.ruoyi.biz.enums.ContractTypeEnum;
import com.ruoyi.biz.enums.ProjectStatusEnum;
import com.ruoyi.biz.mapper.BizCostMapper;
import com.ruoyi.biz.mapper.BizInvoiceMapper;
import com.ruoyi.biz.mapper.BizReceiptMapper;
import com.ruoyi.biz.mapper.BizTopicMapper;
import com.ruoyi.biz.model.req.BizProjectReq;
import com.ruoyi.biz.model.req.StatReq;
import com.ruoyi.biz.model.resp.BizCostResp;
import com.ruoyi.biz.model.resp.BizInvoiceResp;
import com.ruoyi.biz.model.resp.BizProjectResp;
import com.ruoyi.biz.model.resp.BizTopicResp;
import com.ruoyi.biz.model.resp.stat.*;
import com.ruoyi.biz.utils.ReqUtils;
import com.ruoyi.biz.utils.StatUtils;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDeptService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.SecurityUtils.getUserId;
import static com.ruoyi.common.utils.SecurityUtils.isAll;

/**
 * @author tianl
 * @date 2025/2/25
 * @description:
 */
@Service
public class StatProjectService {
    @Autowired
    private BizProjectService bizProjectService;
    @Autowired
    private BizReceiptMapper bizReceiptMapper;
    @Autowired
    private BizTopicMapper bizTopicMapper;
    @Autowired
    private BizInvoiceMapper bizInvoiceMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private BizSectorService bizSectorService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private BizCostMapper bizCostMapper;

    public List<Long> statProject(StatReq req) {
        ReqUtils.setReq(req);
        List<Long> result = new ArrayList<>();
        String difficultLevel = configService.selectConfigByKey("biz.project.difficult.level");
        if (StringUtils.isBlank(difficultLevel)) {
            difficultLevel = "difficult";
        }
        String majorLevel = configService.selectConfigByKey("biz.project.major.level");
        if (StringUtils.isBlank(majorLevel)) {
            majorLevel = "major";
        }
        List<BizProjectResp> projectList = bizProjectService.listStatResp(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
        }
        List<BizSector> sectors = bizSectorService.listDg();
        List<Long> sectorIds = sectors.stream().map(BizSector::getId).collect(Collectors.toList());

        long notDg = projectList.stream()
                .filter(r -> r.getSectorId() != null && sectorIds.contains(r.getSectorId()))
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> !r.getProjectStatus().equals(ProjectStatusEnum.DG.getCode())).count();
        long dg = projectList.stream()
                .filter(r -> r.getSectorId() != null && sectorIds.contains(r.getSectorId()))
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DG.getCode())).count();
        //第10，底稿
        result.add(notDg);
        long unsign = projectList.stream()
                .filter(r -> r.getContractTypeCode() != null)
                .filter(r -> r.getContractTypeCode().equals(ContractTypeEnum.UNSIGN.getValue())).count();
        //第9，未签合同
        result.add(unsign);
        long judicial = projectList.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.JUDICIAL.getCode())).count();
        //第8，转司法
        result.add(judicial);
        long warn = projectList.stream()
                .filter(r -> r.getWarn() != null && r.getWarn()).count();
        //第7，预警
        result.add(warn);
        long due = projectList.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.OVERDUE.getCode())).count();
        //第6，超期
        result.add(due);
        long done = projectList.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DONE.getCode())).count();
        //第5，完成
        result.add(done + dg);
        long doing = projectList.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DOING.getCode())).count();
        //第4，在途
        result.add(doing);
        String finalDifficultLevel = difficultLevel;
        long difficultNum = projectList.stream()
                .filter(r -> r.getLevel() != null)
                .filter(r -> r.getLevel().equals(finalDifficultLevel)).count();
        String finalMajorLevel = majorLevel;
        long majorNum = projectList.stream()
                .filter(r -> r.getLevel() != null)
                .filter(r -> r.getLevel().equals(finalMajorLevel)).count();
        //第3，重大
        result.add(majorNum);
        //第2，疑难
        result.add(difficultNum);
        //第1，累计
        result.add((long) projectList.size());
        return result;
    }

    public List<BigDecimal> statAmount(StatReq req) {
        ReqUtils.setReq(req);
        List<BigDecimal> result = new ArrayList<>();
        StatReq reqAll = new StatReq();
        reqAll.setOutFlag(req.getOutFlag());
        List<BizProject> allList = bizProjectService.listStat(reqAll);
        List<BizProject> projectList = bizProjectService.listStat(req);

        List<Long> projectIds = allList.stream().map(BizProject::getId).collect(Collectors.toList());
        List<Long> allProjectIds = allList.stream().map(BizProject::getId).collect(Collectors.toList());
        BigDecimal totalAmountAll = allList.stream()
                .filter(r -> r.getTotalAmount() != null)
                .map(BizProject::getTotalAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalAmount = projectList.stream()
                .filter(r -> r.getTotalAmount() != null)
                .map(BizProject::getTotalAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal finalProfit = projectList.stream()
                .filter(r -> r.getFinalProfit() != null)
                .map(BizProject::getFinalProfit)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第10，最终利润
        result.add(finalProfit.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<BizProject> performanceProject = allList.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DONE.getCode()) || r.getProjectStatus().equals(ProjectStatusEnum.DG.getCode()))
                .filter(r -> r.getFinishTime() != null && r.getFinishTime().compareTo(req.getTimes().get(0)) >= 0
                        && r.getFinishTime().compareTo(req.getTimes().get(1)) <= 0)
                .collect(Collectors.toList());
        BigDecimal performance = performanceProject.stream()
                .filter(r -> r.getPerformance() != null)
                .map(BizProject::getPerformance)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal marketPerformance = performanceProject.stream()
                .filter(r -> r.getMarketPerformance() != null)
                .map(BizProject::getMarketPerformance)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第9，绩效支出
        result.add(performance.add(marketPerformance).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<Long> dupIds = new ArrayList<>();
        BigDecimal cost1 = BigDecimal.ZERO;
        if(!CollectionUtils.isEmpty(allProjectIds)) {
            List<BizCostResp> costList = bizCostMapper.listByProjectIds(projectIds);
            cost1 = costList.stream()
                    .filter(r -> r.getCostMoney() != null)
                    .map(BizCostResp::getCostMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            dupIds = costList.stream().map(BizCostResp::getId).collect(Collectors.toList());
        }
        if(!CollectionUtils.isEmpty(allProjectIds)){
            List<BizCost> costListOther = bizCostMapper.listStat(allProjectIds,req.getTimes(),dupIds);
            BigDecimal tmp = costListOther.stream()
                    .filter(r -> r.getCostMoney() != null)
                    .map(BizCost::getCostMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            cost1 = cost1.add(tmp);
        }
        //第8，成本支出
        result.add(cost1.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<BizReceipt> receiptList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(allProjectIds)) {
            receiptList = bizReceiptMapper.listEntityByProjectIds(allProjectIds);
        }
        BigDecimal receiptMoneyAll = receiptList.stream()
                .filter(r -> r.getReceiptMoney() != null)
                .map(BizReceipt::getReceiptMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第7，待回款
        result.add(totalAmountAll.subtract(receiptMoneyAll).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<BizReceipt> receiptListTmp;
        if (req.getTimes() != null && req.getTimes().size() >= 2) {
            receiptListTmp = receiptList.stream()
                    .filter(r -> r.getReceiptTime() != null && r.getReceiptTime().compareTo(req.getTimes().get(0)) >= 0
                            && r.getReceiptTime().compareTo(req.getTimes().get(1)) <= 0)
                    .collect(Collectors.toList());
        } else {
            receiptListTmp = receiptList.stream()
                    .filter(r -> r.getReceiptTime() != null)
                    .collect(Collectors.toList());
        }
        BigDecimal receiptMoney = receiptListTmp.stream()
                .filter(r -> r.getReceiptMoney() != null)
                .map(BizReceipt::getReceiptMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第6，已回款
        result.add(receiptMoney.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<BizInvoiceResp> invoices = new ArrayList<>();
        if(!CollectionUtils.isEmpty(allProjectIds)) {
            invoices = bizInvoiceMapper.listByProjectIds(allProjectIds);
        }
        BigDecimal invoicesAmountAll = invoices.stream()
                .filter(r -> r.getInvoiceMoney() != null)
                .map(BizInvoiceResp::getInvoiceMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第5，待开票
        result.add(totalAmountAll.subtract(invoicesAmountAll).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        List<BizInvoiceResp> invoicesTmp;
        if (req.getTimes() != null && req.getTimes().size() >= 2) {
            invoicesTmp = invoices.stream()
                    .filter(r -> r.getInvoiceTime() != null && r.getInvoiceTime().compareTo(req.getTimes().get(0)) >= 0
                            && r.getInvoiceTime().compareTo(req.getTimes().get(1)) <= 0)
                    .collect(Collectors.toList());
        } else {
            invoicesTmp = invoices.stream()
                    .filter(r -> r.getInvoiceTime() != null)
                    .collect(Collectors.toList());
        }
        BigDecimal invoicesAmount = invoicesTmp.stream()
                .filter(r -> r.getInvoiceMoney() != null)
                .map(BizInvoiceResp::getInvoiceMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第4，已开票
        result.add(invoicesAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        BigDecimal realIncome = projectList.stream()
                .filter(r -> r.getRealIncome() != null)
                .map(BizProject::getRealIncome)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal realAmount = projectList.stream()
                .filter(r -> r.getRealAmount() != null)
                .map(BizProject::getRealAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //第3，渠道费和渠道税费，合同金额-渠道费-渠道税费=实际收入
        result.add(totalAmount.subtract(realIncome).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        //第2，实际合同额
        result.add(realAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        //第1，合同额
        result.add(totalAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        return result;
    }

    public StatCzBarResp statCzLine(Integer year,Boolean outFlag) {
        StatReq req = ReqUtils.getReq(year);
        req.setOutFlag(outFlag);
        StatCzBarResp statResp = new StatCzBarResp();
        List<BizProject> projectList = bizProjectService.listStat(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return statResp;
        }

        List<Long> projectIds = projectList.stream().map(BizProject::getId).collect(Collectors.toList());

        List<BizReceipt> receiptList = bizReceiptMapper.listEntityByProjectIds(projectIds);
        Map<Integer, List<BizReceipt>> receiptByMonth = receiptList.stream()
                .filter(r -> r.getReceiptTime() != null)
                .collect(Collectors.groupingBy(re -> {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(re.getReceiptTime());
                    return calendar.get(Calendar.MONTH) + 1; // 获取月份，注意月份从0开始，所以要加1
                }));
        Map<Integer, List<BizProject>> groupedByMonth = projectList.stream()
                .filter(r -> r.getSignTime() != null)
                .collect(Collectors.groupingBy(project -> {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(project.getSignTime());
                    return calendar.get(Calendar.MONTH) + 1; // 获取月份，注意月份从0开始，所以要加1
                }));
        List<BigDecimal> monthAmount = new ArrayList<>();
        List<BigDecimal> monthRealAmount = new ArrayList<>();
        List<BigDecimal> monthReceiptAmount = new ArrayList<>();
        List<BigDecimal> monthUnReceiptAmount = new ArrayList<>();
        List<Integer> monthProjectNum = new ArrayList<>();
        int month = 0;
        Calendar calendar = Calendar.getInstance();
        if (year == calendar.get(Calendar.YEAR)) {
            month = calendar.get(Calendar.MONTH) + 1;
        } else if (year < calendar.get(Calendar.YEAR)) {
            month = 12;
        }
        for (int i = 1; i <= month; i++) {
            BigDecimal tmpTotal = BigDecimal.ZERO;
            BigDecimal tmpRealAmount = BigDecimal.ZERO;
            int projectNum = 0;
            if (groupedByMonth.containsKey(i)) {
                tmpTotal = groupedByMonth.get(i).stream()
                        .filter(r -> r.getTotalAmount() != null)
                        .map(BizProject::getTotalAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                tmpRealAmount = groupedByMonth.get(i).stream()
                        .filter(r -> r.getRealAmount() != null)
                        .map(BizProject::getRealAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                projectNum = groupedByMonth.get(i).size();
            }
            monthAmount.add(tmpTotal.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthRealAmount.add(tmpRealAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthProjectNum.add(projectNum);
            BigDecimal tmpReceipt = BigDecimal.ZERO;
            if (receiptByMonth.containsKey(i)) {
                tmpReceipt = receiptByMonth.get(i).stream()
                        .filter(r -> r.getReceiptMoney() != null)
                        .map(BizReceipt::getReceiptMoney)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            monthReceiptAmount.add(tmpReceipt.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthUnReceiptAmount.add(tmpTotal.subtract(tmpReceipt).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        }
        statResp.setMonthAmount(monthAmount);
        statResp.setMonthReceiptAmount(monthReceiptAmount);
        statResp.setMonthRealAmount(monthRealAmount);
        statResp.setMonthUnReceiptAmount(monthUnReceiptAmount);
        statResp.setMonthProjectNum(monthProjectNum);
        return statResp;
    }

    public List<StatYjBarResp> statYjLine(Integer year,Boolean outFlag) {
        List<StatYjBarResp> result = new ArrayList<>();
        StatYjBarResp statResp = getYjLine(year,outFlag);
        StatYjBarResp statLastResp = getYjLine(year - 1,outFlag);
        result.add(statResp);
        result.add(statLastResp);
        return result;
    }

    public StatDeptBarResp statDeptBar(Integer year,Boolean outFlag) {
        StatReq req = ReqUtils.getReq(year);
        req.setOutFlag(outFlag);
        StatDeptBarResp statResp = new StatDeptBarResp();
        List<BizProject> projectList = bizProjectService.listStat(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return statResp;
        }
        SysDept sysDeptReq = new SysDept();
        sysDeptReq.setParentId(100L);
        List<SysDept> deptList = deptService.selectDeptListAll(sysDeptReq);
        if (CollectionUtils.isEmpty(deptList)) {
            return statResp;
        }
        String difficultLevel = configService.selectConfigByKey("biz.project.difficult.level");
        if (StringUtils.isBlank(difficultLevel)) {
            difficultLevel = "difficult";
        }
        List<Long> projectIds = projectList.stream().map(BizProject::getId).collect(Collectors.toList());

        List<BizReceipt> receiptList = bizReceiptMapper.listEntityByProjectIds(projectIds);
        Map<Long, List<BizReceipt>> receiptByMonth = receiptList.stream()
                .collect(Collectors.groupingBy(BizReceipt::getProjectId));
        Map<Long, List<BizProject>> groupedByDept = projectList.stream()
                .filter(r -> r.getEnforceDeptId() != null)
                .collect(Collectors.groupingBy(BizProject::getEnforceDeptId));
        Map<Long, List<BizProject>> groupedByCreateDept = projectList.stream()
                .filter(r -> r.getDeptId() != null)
                .collect(Collectors.groupingBy(BizProject::getDeptId));
        List<String> deptNames = new ArrayList<>();
        List<BigDecimal> monthAmount = new ArrayList<>();
        List<BigDecimal> monthChannelAmount = new ArrayList<>();
        List<BigDecimal> monthChannelTaxAmount = new ArrayList<>();
        List<BigDecimal> monthReceiptAmount = new ArrayList<>();
        List<BigDecimal> monthUnReceiptAmount = new ArrayList<>();
        List<Integer> monthProjectNum = new ArrayList<>();
        List<Integer> enforceTotalProjectNum = new ArrayList<>();
        List<Long> enforceRunProjectNum = new ArrayList<>();
        List<Long> enforceDoneProjectNum = new ArrayList<>();
        List<Long> enforceDiffProjectNum = new ArrayList<>();
        for (SysDept sysDept : deptList) {
            deptNames.add(sysDept.getDeptName());
            List<SysDept> childDept = deptService.listNormalChildrenDeptById(sysDept.getDeptId());
            List<Long> childDeptIds = childDept.stream().map(SysDept::getDeptId).collect(Collectors.toList());
            childDeptIds.add(sysDept.getDeptId());
            BigDecimal monthTmpAmount = BigDecimal.ZERO;
            BigDecimal monthTmpChannelAmount = BigDecimal.ZERO;
            BigDecimal monthTmpChannelTaxAmount = BigDecimal.ZERO;
            BigDecimal monthTmpReceiptAmount = BigDecimal.ZERO;
            BigDecimal monthTmpUnReceiptAmount = BigDecimal.ZERO;
            int monthTmpProjectNum = 0;
            int enforceTmpTotalProjectNum = 0;
            long enforceTmpRunProjectNum = 0L;
            long enforceTmpDoneProjectNum = 0L;
            long enforceTmpDiffProjectNum = 0L;
            for (Long childDeptId : childDeptIds) {
                List<BizProject> enforceList = groupedByDept.get(childDeptId);
                if (enforceList == null) {
                    enforceList = new ArrayList<>();
                }
                List<BizProject> createList = groupedByCreateDept.get(childDeptId);
                if (createList == null) {
                    createList = new ArrayList<>();
                }
                BigDecimal tmpTotal = BigDecimal.ZERO;
                BigDecimal tmpRealAmount = BigDecimal.ZERO;
                BigDecimal tmpRealIncome = BigDecimal.ZERO;

                tmpTotal = createList.stream()
                        .filter(r -> r.getTotalAmount() != null)
                        .map(BizProject::getTotalAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                tmpRealAmount = createList.stream()
                        .filter(r -> r.getRealAmount() != null)
                        .map(BizProject::getRealAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                tmpRealIncome = createList.stream()
                        .filter(r -> r.getRealIncome() != null)
                        .map(BizProject::getRealIncome)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                BigDecimal tmpChannelAmount = tmpTotal.subtract(tmpRealAmount);
                BigDecimal tmpChannelTaxAmount = tmpRealAmount.subtract(tmpRealIncome);
                monthTmpAmount = monthTmpAmount.add(tmpTotal);
                monthTmpChannelAmount = monthTmpChannelAmount.add(tmpChannelAmount);
                monthTmpChannelTaxAmount = monthTmpChannelTaxAmount.add(tmpChannelTaxAmount);
                monthTmpProjectNum += createList.size();
                BigDecimal tmpReceipt = BigDecimal.ZERO;
                for (BizProject bizProject : createList) {
                    if (receiptByMonth.containsKey(bizProject.getId())) {
                        tmpReceipt = tmpReceipt.add(
                                receiptByMonth.get(bizProject.getId()).stream()
                                        .filter(r -> r.getReceiptMoney() != null)
                                        .map(BizReceipt::getReceiptMoney)
                                        .reduce(BigDecimal.ZERO, BigDecimal::add));
                    }
                }
                monthTmpReceiptAmount = monthTmpReceiptAmount.add(tmpReceipt);
                monthTmpUnReceiptAmount = monthTmpUnReceiptAmount.add(tmpTotal.subtract(tmpReceipt));

                enforceTmpTotalProjectNum += enforceList.size();
                long doing = enforceList.stream()
                        .filter(r -> r.getProjectStatus() != null)
                        .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DOING.getCode())).count();
                enforceTmpRunProjectNum += doing;
                long done = enforceList.stream()
                        .filter(r -> r.getProjectStatus() != null)
                        .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DONE.getCode())).count();
                enforceTmpDoneProjectNum += done;
                String finalDifficultLevel = difficultLevel;
                long differentNum = enforceList.stream()
                        .filter(r -> r.getLevel() != null)
                        .filter(r -> r.getLevel().equals(finalDifficultLevel)).count();
                enforceTmpDiffProjectNum += differentNum;
            }
            monthAmount.add(monthTmpAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthChannelAmount.add(monthTmpChannelAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthChannelTaxAmount.add(monthTmpChannelTaxAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthProjectNum.add(monthTmpProjectNum);
            monthReceiptAmount.add(monthTmpReceiptAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthUnReceiptAmount.add(monthTmpUnReceiptAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            enforceTotalProjectNum.add(enforceTmpTotalProjectNum);
            enforceRunProjectNum.add(enforceTmpRunProjectNum);
            enforceDoneProjectNum.add(enforceTmpDoneProjectNum);
            enforceDiffProjectNum.add(enforceTmpDiffProjectNum);
        }

        statResp.setDeptList(deptNames);
        statResp.setMonthAmount(monthAmount);
        statResp.setMonthReceiptAmount(monthReceiptAmount);
        statResp.setMonthChannelAmount(monthChannelAmount);
        statResp.setMonthChannelTaxAmount(monthChannelTaxAmount);
        statResp.setMonthUnReceiptAmount(monthUnReceiptAmount);
        statResp.setMonthProjectNum(monthProjectNum);
        statResp.setEnforceTotalProjectNum(enforceTotalProjectNum);
        statResp.setEnforceRunProjectNum(enforceRunProjectNum);
        statResp.setEnforceDoneProjectNum(enforceDoneProjectNum);
        statResp.setEnforceDiffProjectNum(enforceDiffProjectNum);
        return statResp;
    }

    public StatSectorBarResp statSectorBar(Integer year) {
        StatReq req = ReqUtils.getReq(year);
        String difficultLevel = configService.selectConfigByKey("biz.project.difficult.level");
        if (StringUtils.isBlank(difficultLevel)) {
            difficultLevel = "difficult";
        }
        StatSectorBarResp statResp = new StatSectorBarResp();
        List<BizProject> projectList = bizProjectService.listStat(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return statResp;
        }
        List<BizSector> allSectorList = bizSectorService.list();
        List<BizSector> parentSectorList = allSectorList.stream()
                .filter(r -> r.getParentId() == 0).collect(Collectors.toList());
        List<BizSector> childSectorList = allSectorList.stream()
                .filter(r -> r.getParentId() != 0).collect(Collectors.toList());
        List<String> nameList = new ArrayList<>();
        List<Integer> projectNum = new ArrayList<>();
        List<Long> doingNum = new ArrayList<>();
        List<Long> doneNum = new ArrayList<>();
        List<Long> difficultNum = new ArrayList<>();
        for (BizSector sector : parentSectorList) {
            nameList.add(sector.getName());
            List<BizSector> sectorList = StatUtils.pack(sector.getId(), childSectorList);
            List<Long> sectorIds = sectorList.stream().map(BizSector::getId).collect(Collectors.toList());
            sectorIds.add(sector.getId());
            List<BizProject> tmp = projectList.stream()
                    .filter(r -> sectorIds.contains(r.getSectorId())).collect(Collectors.toList());
            String finalDifficultLevel = difficultLevel;
            projectNum.add(tmp.size());
            long doing = tmp.stream()
                    .filter(r -> r.getProjectStatus() != null)
                    .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DOING.getCode())).count();
            doingNum.add(doing);
            long done = tmp.stream()
                    .filter(r -> r.getProjectStatus() != null)
                    .filter(r ->
                            r.getProjectStatus().equals(ProjectStatusEnum.DONE.getCode())
                                    || r.getProjectStatus().equals(ProjectStatusEnum.DG.getCode())
                    ).count();
            doneNum.add(done);
            long difficult = tmp.stream()
                    .filter(r -> r.getLevel() != null)
                    .filter(r -> r.getLevel().equals(finalDifficultLevel)).count();
            difficultNum.add(difficult);
        }
        statResp.setNameList(nameList);
        statResp.setProjectNum(projectNum);
        statResp.setDoingNum(doingNum);
        statResp.setDoneNum(doneNum);
        statResp.setDifficultNum(difficultNum);
        return statResp;
    }

    public StatTopicResp statTopic() {
        StatTopicResp statResp = new StatTopicResp();
        StatReq req = new StatReq();
        req.setPage(true);
        List<BizProjectResp> projectList = bizProjectService.listStat2(req);
        List<BizProjectResp> projectList2 = bizProjectService.listStat2(new StatReq());
        if (CollectionUtils.isEmpty(projectList)) {
            return statResp;
        }

        List<BizProjectResp> topicNotDoneList = projectList.stream().filter(r -> r.getProjectStatus()<98).collect(Collectors.toList());
        topicNotDoneList.sort(Comparator.comparing(BizProject::getDeadline));
        List<BizTopicResp> list = new ArrayList<>();
        for(BizProjectResp bizProject : topicNotDoneList){
            BizTopicResp resp = new BizTopicResp();
            resp.setTopicName(bizProject.getProjectName());
            resp.setStatusName(ProjectStatusEnum.getNameByCode(bizProject.getProjectStatus()));
            resp.setEndTime(bizProject.getDeadline());
            resp.setWarn(bizProject.getWarn());
            resp.setDue(bizProject.getProjectStatus().equals(ProjectStatusEnum.OVERDUE.getCode()));
            list.add(resp);
        }
        long topicDueNum = projectList2.stream().filter(r->r.getProjectStatus().equals(ProjectStatusEnum.OVERDUE.getCode())).count();
        statResp.setTopicList(list);
        statResp.setTopicDueNum(topicDueNum);
        return statResp;
    }

    public StatYjBarResp getYjLine(Integer year,Boolean outFlag) {
        StatReq req = ReqUtils.getReq(year);
        req.setOutFlag(outFlag);
        StatYjBarResp statResp = new StatYjBarResp();
        List<BizProject> projectList = bizProjectService.listStat(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return statResp;
        }

        List<Long> projectIds = projectList.stream().map(BizProject::getId).collect(Collectors.toList());

        List<BizReceipt> receiptList = bizReceiptMapper.listEntityByProjectIds(projectIds);
        Map<Integer, List<BizReceipt>> receiptByMonth = receiptList.stream()
                .filter(r -> r.getReceiptTime() != null)
                .collect(Collectors.groupingBy(re -> {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(re.getReceiptTime());
                    return calendar.get(Calendar.MONTH) + 1;
                }));
        Map<Integer, List<BizProject>> groupedByMonth = projectList.stream()
                .filter(r -> r.getSignTime() != null)
                .collect(Collectors.groupingBy(project -> {
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(project.getSignTime());
                    return calendar.get(Calendar.MONTH) + 1;
                }));
        List<BigDecimal> monthAmount = new ArrayList<>();
        List<BigDecimal> monthReceiptAmount = new ArrayList<>();
        List<BigDecimal> monthUnReceiptAmount = new ArrayList<>();
        List<BigDecimal> monthChannelAmount = new ArrayList<>();
        List<BigDecimal> monthChannelTaxAmount = new ArrayList<>();
        List<BigDecimal> monthCostAmount = new ArrayList<>();
        List<BigDecimal> monthSfAmount = new ArrayList<>();
        List<BigDecimal> monthPerformanceAmount = new ArrayList<>();
        int month = 0;
        Calendar calendar = Calendar.getInstance();
        if (year == calendar.get(Calendar.YEAR)) {
            month = calendar.get(Calendar.MONTH) + 1;
        } else if (year < calendar.get(Calendar.YEAR)) {
            month = 12;
        }
        for (int i = 1; i <= month; i++) {
            BigDecimal tmpTotal = BigDecimal.ZERO;
            BigDecimal tmpChannelAmount = BigDecimal.ZERO;
            BigDecimal tmpChannelTaxAmount = BigDecimal.ZERO;
            BigDecimal tmpCostAmount = BigDecimal.ZERO;
            BigDecimal tmpSfAmount = BigDecimal.ZERO;
            BigDecimal tmpPerformanceAmount = BigDecimal.ZERO;
            if (groupedByMonth.containsKey(i)) {
                tmpTotal = groupedByMonth.get(i).stream()
                        .filter(r -> r.getTotalAmount() != null)
                        .map(BizProject::getTotalAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal tmpRealAmount = groupedByMonth.get(i).stream()
                        .filter(r -> r.getRealAmount() != null)
                        .map(BizProject::getRealAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal tmpRealIncome = groupedByMonth.get(i).stream()
                        .filter(r -> r.getRealIncome() != null)
                        .map(BizProject::getRealIncome)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                tmpCostAmount = groupedByMonth.get(i).stream()
                        .filter(r -> r.getBaseCost() != null)
                        .map(BizProject::getBaseCost)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal performance = projectList.stream()
                        .filter(r -> r.getPerformance() != null)
                        .map(BizProject::getPerformance)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal marketPerformance = projectList.stream()
                        .filter(r -> r.getMarketPerformance() != null)
                        .map(BizProject::getMarketPerformance)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                tmpPerformanceAmount = performance.add(marketPerformance);
                tmpChannelAmount = tmpTotal.subtract(tmpRealAmount);
                tmpChannelTaxAmount = tmpRealAmount.subtract(tmpRealIncome);
                tmpSfAmount = tmpTotal.multiply(BigDecimal.valueOf(0.1));
            }
            monthAmount.add(tmpTotal.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthChannelAmount.add(tmpChannelAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthChannelTaxAmount.add(tmpChannelTaxAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthCostAmount.add(tmpCostAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthSfAmount.add(tmpSfAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthPerformanceAmount.add(tmpPerformanceAmount.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            BigDecimal tmpReceipt = BigDecimal.ZERO;
            if (receiptByMonth.containsKey(i)) {
                tmpReceipt = receiptByMonth.get(i).stream()
                        .filter(r -> r.getReceiptMoney() != null)
                        .map(BizReceipt::getReceiptMoney)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            monthReceiptAmount.add(tmpReceipt.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
            monthUnReceiptAmount.add(tmpTotal.subtract(tmpReceipt).divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP));
        }
        statResp.setMonthAmount(monthAmount);
        statResp.setMonthReceiptAmount(monthReceiptAmount);
        statResp.setMonthUnReceiptAmount(monthUnReceiptAmount);
        statResp.setMonthChannelAmount(monthChannelAmount);
        statResp.setMonthChannelTaxAmount(monthChannelTaxAmount);
        statResp.setMonthCostAmount(monthCostAmount);
        statResp.setMonthSfAmount(monthSfAmount);
        statResp.setMonthPerformanceAmount(monthPerformanceAmount);
        return statResp;
    }
}
